import mockmodules.mock_test_module
import mockmodules.mock_test_module_with_3_passing_2_failing_1_ignored_tests
from testudo import Assert, simplejson
from testudo.framework import *
from mocks import *

'''
class FailingTests():
	def test_fails(self):
		Assert.fail("failed")
	
	def test_unexpected_exception(self):
		raise Exception("message")

	def test_ignored(self):
		Assert.ignore("my lovely ignore message")
'''


class FixtureRunnerTests():
	def test_should_call_test_methods_when_no_setup_and_teardown_exists(self):
		mock_test = MockTestFixtureWithoutSetUpAndTearDown()
		runner = FixtureRunner(mock_test)
		runner.run();
		Assert.are_equal(2, len(mock_test.invoked_methods))
		Assert.are_equal("test_method_1", mock_test.invoked_methods[0])
		Assert.are_equal("test_method_2", mock_test.invoked_methods[1])
	
	def test_should_call_setup_and_tear_down_when_appropriate(self):
		mock_test = MockTestFixtureWithSetUpAndTearDown()
		runner = FixtureRunner(mock_test)
		runner.run()
		Assert.are_equal(6, len(mock_test.invoked_methods))
		Assert.are_equal("set_up", mock_test.invoked_methods[0])
		Assert.are_equal("test_method_1", mock_test.invoked_methods[1])
		Assert.are_equal("tear_down", mock_test.invoked_methods[2])
		Assert.are_equal("set_up", mock_test.invoked_methods[3])
		Assert.are_equal("test_method_2", mock_test.invoked_methods[4])
		Assert.are_equal("tear_down", mock_test.invoked_methods[5])
		
	def test_tear_down_should_be_called_even_if_the_test_fails(self):
		mock_test = MockTestFixtureWithTearDownAndFailingTest()
		runner = FixtureRunner(mock_test)
		runner.run()
		Assert.are_equal(2, len(mock_test.invoked_methods))
		Assert.are_equal("test_fails", mock_test.invoked_methods[0])
		Assert.are_equal("tear_down", mock_test.invoked_methods[1])
	
	def test_tear_down_should_be_called_even_if_an_exception_occurs_in_set_up(self):
		mock_test = MockTestFixtureWithTearDownAndExceptionInSetUp()
		runner = FixtureRunner(mock_test)
		runner.run()
		Assert.are_equal(2, len(mock_test.invoked_methods))
		Assert.are_equal("set_up", mock_test.invoked_methods[0])
		Assert.are_equal("tear_down", mock_test.invoked_methods[1])
	
	def test_result_for_successful_test(self):
		mock_test = MockTestFixtureWithSuccessfulTest()
		runner = FixtureRunner(mock_test)
		result = runner.run()
		Assert.are_equal(1, len(result.test_results))
		self.assert_test_result("test_success", True, "", False, result.test_results[0])
		
	def test_result_for_failing_test(self):
		mock_test = MockTestFixtureWithFailingTest()
		runner = FixtureRunner(mock_test)
		result = runner.run()
		Assert.are_equal(1, len(result.test_results))
		self.assert_test_result("test_fail", False, "message", False, result.test_results[0])
		self.assert_stack_trace("mocks.py", "AssertionException: message", "test_fail", result.test_results[0].stack_trace)
	
	def test_result_for_unexpected_exception(self):
		mock_test = MockTestFixtureWithException()
		runner = FixtureRunner(mock_test)
		result = runner.run().test_results[0]
		self.assert_test_result("test_exception", False, "TestException : exception message", False, result)
		self.assert_stack_trace("mocks.py", "TestException: exception message", "test_exception", result.stack_trace)

	def test_result_for_ignored_test(self):
		mock_test = MockTestFixtureWithIgnoredTest()
		runner = FixtureRunner(mock_test)
		result = runner.run().test_results[0]
		Assert.is_true(result.is_ignored, "is_ignored should be true")
		self.assert_test_result("test_ignored", False, "ignore message", True, result)
	
	def test_fixture_result_for_3_passing_tests(self):
		mock_test = MockTestFixtureWith3Tests_()
		result = FixtureRunner(mock_test).run()
		assert_test_count(3, 3, 0, 0, result)
		Assert.is_true(result.is_successful())
	
	def test_fixture_result_for_0_tests(self):
		mock_test = MockTestFixtureWith0Test()
		result = FixtureRunner(mock_test).run()
		assert_test_count(0, 0, 0, 0, result)
		Assert.is_true(result.is_successful())
		
	def test_fixture_result_for_1_passing_and_1_failing_tests(self):
		mock_test = MockTestFixtureWith1PassingAnd1FailingTests_()
		result = FixtureRunner(mock_test).run()
		assert_test_count(2, 1, 1, 0, result)
		Assert.is_false(result.is_successful())

	def test_fixture_result_for_1_passing_and_1_ignored_tests(self):
		mock_test = MockTestFixtureWith1PassingAnd1IgnoredTests_()
		result = FixtureRunner(mock_test).run()
		assert_test_count(2, 1, 0, 1, result)
		Assert.is_true(result.is_successful())

	def assert_test_result(self, expected_method_name, expected_success, expected_message, expected_ignore, actual_result):
		Assert.are_equal(expected_method_name, actual_result.method_name)
		Assert.are_equal(expected_success, actual_result.is_successful, "is_successful failed")
		Assert.are_equal(expected_message, actual_result.message)	
		Assert.are_equal(expected_ignore, actual_result.is_ignored, "is_ignore failed")

	def assert_stack_trace(self, expected_name, expected_exception_string, expected_function_name, actual_stack_trace):
		Assert.is_true(expected_name in actual_stack_trace, "Should contain module file module_name")
		Assert.is_true(expected_exception_string in actual_stack_trace, "Should contain exception module_name and message")
		Assert.is_true(expected_function_name in actual_stack_trace, "Should contain function module_name")
		
class ModuleRunnerTests():
	def test_should_run_mock_module(self):
		mock_module = eval("mockmodules.mock_test_module")
		results = ModuleRunner(mock_module).run()
		Assert.are_equal("mockmodules.mock_test_module", results.module_name)
		Assert.are_equal(2, len(results.fixture_results))
		
	def test_count_for_3_passing_2_ignored_1_failing_tests(self):
		mock_module = eval("mockmodules.mock_test_module_with_3_passing_2_failing_1_ignored_tests")
		results = ModuleRunner(mock_module).run()
		assert_test_count(6, 3, 2, 1, results)
		
class SuiteRunnerTests():
	def test_should_run_all_tests_in_a_package(self):
		result = SuiteRunner(["suiterunnertestpackage1"]).run()
		Assert.are_equal(2, len(result.module_results), "Number of module module_results is wrong")
		Assert.are_equal("suiterunnertestpackage1.test_module_1", result.module_results[0].module_name)
		Assert.are_equal("suiterunnertestpackage1.test_module_2", result.module_results[1].module_name)
		assert_test_count(2, 2, 0, 0, result)
		
		
	def test_should_run_all_tests_in_two_packages(self):
		result = SuiteRunner(["suiterunnertestpackage1", "suiterunnertestpackage2"]).run()
		Assert.are_equal(5, len(result.module_results), "Number of module module_results is wrong")
		Assert.are_equal("suiterunnertestpackage1.test_module_1", result.module_results[0].module_name)
		Assert.are_equal("suiterunnertestpackage1.test_module_2", result.module_results[1].module_name)
		Assert.are_equal("suiterunnertestpackage2.test_module_3", result.module_results[2].module_name)
		Assert.are_equal("suiterunnertestpackage2.test_module_4", result.module_results[3].module_name)
		Assert.are_equal("suiterunnertestpackage2.test_module_5", result.module_results[4].module_name)
		assert_test_count(5, 3, 1, 1, result)
	
	def test_should_calculate_total_running_time(self):
		self.assert_total_run_time(3, 25, 28)
		self.assert_total_run_time(15, 5, 20)		
		
	def assert_total_run_time(self, expected_total_run_time, start_time, finish_time):
		stub_clock = StubClock()
		stub_clock.first_time = start_time
		stub_clock.second_time = finish_time		
				
		suite_runner = SuiteRunner(["suiterunnertestpackage1"])
		suite_runner.clock = stub_clock
		result = suite_runner.run()
	
		Assert.are_equal(expected_total_run_time, result.total_run_time, "total_run_time wrong")
		
class TestResultTests():
	def test_to_json_for_successful_test(self):
		test_result = TestResult.create_success("test_method")
		test_result_json = test_result.to_json()

		self.assert_test_result_json("test_method", True, "", "", False, test_result_json)
		
	def test_to_json_for_ignored_test(self):
		test_result = TestResult.create_ignore("test_ignored", "ignore message")
		test_result_json = test_result.to_json()

		self.assert_test_result_json("test_ignored", False, "ignore message", "", True, test_result_json)
		
	def test_to_json_for_failing_test(self):
		test_result = TestResult.create_fail("failing_test", "fail message", "stack trace")
		test_result_json = test_result.to_json()
		
		self.assert_test_result_json("failing_test", False, "fail message", "stack trace", False, test_result_json)
		
	def assert_test_result_json(self, expected_method_name, expected_is_successful,
									expected_message, expected_stack_trace,
									expected_is_ignored, actual_test_result_json):
		Assert.are_equal(expected_method_name, actual_test_result_json["method_name"])
		Assert.are_equal(expected_is_successful, actual_test_result_json["is_successful"], "is_successful should be False.")
		Assert.are_equal(expected_message, actual_test_result_json["message"])
		Assert.are_equal(expected_stack_trace, actual_test_result_json["stack_trace"])
		Assert.are_equal(expected_is_ignored, actual_test_result_json["is_ignored"], "is_ignored should be True.")
		
class FixtureResultTests():
	def test_to_json_for_empty_fixture_result(self):
		fixture_result = FixtureResult("test_fixture")
		fixture_result_json = fixture_result.to_json()
		
		Assert.are_equal("test_fixture", fixture_result_json["fixture_name"])
		Assert.are_equal(True, fixture_result_json["is_successful"])
		Assert.are_equal(0, len(fixture_result_json["test_results"]))
		
	def test_to_json_for_fixture_result_with_three_test_results(self):
		test_result_success = TestResult.create_success("test_success")
		test_result_ignore = TestResult.create_ignore("test_ignore", "ignore message")
		test_result_fail = TestResult.create_fail("test_fail", "message", "stack trace")
		
		fixture_result = FixtureResult("test_fixture_with_two_test_results")
		fixture_result.add_test_result(test_result_success)
		fixture_result.add_test_result(test_result_ignore)
		fixture_result.add_test_result(test_result_fail)
		
		fixture_result_json = fixture_result.to_json()
		Assert.are_equal("test_fixture_with_two_test_results", fixture_result_json["fixture_name"])
		Assert.are_equal(False, fixture_result_json["is_successful"])
		Assert.are_equal(3, len(fixture_result_json["test_results"]))
		assert_json_equal(test_result_success.to_json(), fixture_result_json["test_results"][0])
		assert_json_equal(test_result_ignore.to_json(), fixture_result_json["test_results"][1])
		assert_json_equal(test_result_fail.to_json(), fixture_result_json["test_results"][2])
		

class ModuleResultTests():
	def test_to_json_for_empty_module_result(self):
		module_result = ModuleResult("module_name")
		module_result_json = module_result.to_json()
		
		Assert.are_equal("module_name", module_result_json["module_name"])
		Assert.is_true(module_result_json["is_successful"])
		Assert.are_equal(0, len(module_result_json["fixture_results"]))
		
	def test_to_json_for_module_result_with_two_fixture_results(self):
		fixture_result_1 = StubFixtureResult(False, "first_test_fixture json")
		fixture_result_2 = StubFixtureResult(True, "second_test_fixture json")
		
		module_result = ModuleResult("module_with_two_test_fixtures")
		module_result.add_result(fixture_result_1)
		module_result.add_result(fixture_result_2)		
		
		module_result_json = module_result.to_json()
		
		Assert.are_equal("module_with_two_test_fixtures", module_result_json["module_name"])
		Assert.is_false(module_result_json["is_successful"])
		Assert.are_equal(2, len(module_result_json["fixture_results"]))
		assert_json_equal(fixture_result_1.to_json(), module_result_json["fixture_results"][0])
		assert_json_equal(fixture_result_2.to_json(), module_result_json["fixture_results"][1])		

	def test_to_json_for_module_result_with_one_passing_tests(self):
		fixture_result = StubFixtureResult(True, "")
		
		module_result = ModuleResult("")
		module_result.add_result(fixture_result)
		
		Assert.is_true(module_result.to_json()["is_successful"])
		
class SuiteResultTests():
	def test_to_json_for_empty_suite_result(self):
		suite_result = SuiteResult()
		suite_result_json = suite_result.to_json()
		
		Assert.is_true(suite_result_json["is_successful"])
		Assert.are_equal(0, len(suite_result_json["module_results"]))
		
	def test_to_json_for_suite_result_with_two_modules(self):
		module_result_1 = ModuleResult("first_module_result")
		module_result_2 = ModuleResult("second_module_result")
		
		suite_result = SuiteResult()
		suite_result.add_result(module_result_1)
		suite_result.add_result(module_result_2)
		
		suite_result_json = suite_result.to_json()
		
		Assert.are_equal(2, len(suite_result_json["module_results"]))
		assert_json_equal(module_result_1.to_json(), suite_result_json["module_results"][0])	
		assert_json_equal(module_result_2.to_json(), suite_result_json["module_results"][1])	

	def test_to_json_statistics(self):
		module_result_1 = StubModuleResult(4, 2, 1, 1, False)
		module_result_2 = StubModuleResult(6, 3, 2, 1, False)

		suite_result = SuiteResult()
		suite_result.add_result(module_result_1)
		suite_result.add_result(module_result_2)
		suite_result.total_run_time = 4

		suite_result_json = suite_result.to_json()
		
		Assert.is_false(suite_result_json["is_successful"], "is successful should be false")
		Assert.are_equal(10, suite_result_json["total_test_count"], "total_test_count failed.")
		Assert.are_equal(5, suite_result_json["passing_test_count"], "passing_test_count failed.")
		Assert.are_equal(3, suite_result_json["failing_test_count"], "failing_test_count failed.")
		Assert.are_equal(2, suite_result_json["ignored_test_count"], "ignored_test_count failed.")
		Assert.are_equal(4, suite_result_json["total_run_time"], "total_run_time failed.")
		
	def test_to_json_for_one_passing_module(self):
		module_result = StubModuleResult(4, 4, 0, 0, True)
		
		suite_result = SuiteResult()
		suite_result.add_result(module_result)
				
		Assert.is_true(suite_result.to_json()["is_successful"])
		
def assert_json_equal(expected_json_object, actual_json_object):
	return Assert.are_equal(
						simplejson.dumps(expected_json_object),
						simplejson.dumps(actual_json_object))

def assert_test_count(expected_total_count, expected_passing_count, expected_failing_count, expected_ignored_count, actual_result):
	Assert.are_equal(expected_total_count, actual_result.total_test_count(), "Total count failed.")
	Assert.are_equal(expected_passing_count, actual_result.passing_test_count(), "Passing count failed.")
	Assert.are_equal(expected_failing_count, actual_result.failing_test_count(), "Failing count failed.")
	Assert.are_equal(expected_ignored_count, actual_result.ignored_test_count(), "Ignored count failed.")

class StubModuleResult():
	def __init__(self, total_test_count, passing_test_count, failing_test_count, ignored_test_count, is_successful):
		self.total_count = total_test_count
		self.passing_count = passing_test_count
		self.ignored_count = ignored_test_count
		self.failing_count = failing_test_count
		self.is_successful_value = is_successful
		
	def is_successful(self):
		return self.is_successful_value
	
	def total_test_count(self):
		return self.total_count;
	
	def passing_test_count(self):
		return self.passing_count
	
	def failing_test_count(self):
		return self.failing_count
	
	def ignored_test_count(self):
		return self.ignored_count
		
	def to_json(self):		
		return {}

class StubFixtureResult():
	def __init__(self, is_successful, json):
		self.is_successful_value = is_successful
		self.json_value = json
		
	def is_successful(self):
		return self.is_successful_value
	
	def to_json(self):
		return self.json_value

class StubClock():
	def __init__(self):
		self.first_time = 0
		self.second_time = 0
		self.is_first_call = True
	
	def time(self):
		if self.is_first_call:
			self.is_first_call = False
			return self.first_time
		else:
			return self.second_time